home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_065 / prep / macro.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  19KB  |  709 lines

  1. /* MACRO.c
  2.  *
  3.  *   The routines in this file support the macro processing facilities
  4.  * of PREP.  The style is similar to that of c #define macros, except
  5.  * that : is used instead of #define and ; terminates the macro.  
  6.  *   Recursive definitions are permitted, but will cause an abort
  7.  * (and possibly a memory allocation error) on expansion.  For each
  8.  * line submitted to expand_macros, a count of is kept for each
  9.  * stored macro indicating how many times it has been expanded in
  10.  * the current line.  When this exceeds MAX_CALLS, the program 
  11.  * assumes a macro definition is recursive and stops.  Macros
  12.  * are expanded starting with the one with the longest name, so that
  13.  * if the definitions
  14.  *
  15.  * : >=        .ge. ;
  16.  * : >        .gt. ;
  17.  *
  18.  * are in effect, >= will be changed to .ge. rather than .gt.=.  This
  19.  * is only a potential problem when macro names are not fully
  20.  * alphanumeric, since "arg" will not be flagged if "r" is defined.
  21.  *   If a definition contains no test ( : name ; ) then name is
  22.  * removed from the list if present.  This can be used for undefining
  23.  * macro defs.
  24.  *
  25.  * 11/4/86 P.R.OVE
  26.  */
  27.  
  28.  
  29. #include "prep.h"
  30.  
  31. #define    MAX_MACROS    1000
  32. #define MAX_CALLS    100    /* if exceeded, assume recursive */
  33. #define MAXCHAR        127    /* max ascii char allowed in names (for bm) */
  34.  
  35. /* macro structure */
  36. struct Macro {
  37.     char    *name ;        /* macro name */
  38.     int    namelength ;    /* macro name length */
  39.     char    *text ;        /* text with parm codes */
  40.     int    parmcount ;    /* number of parms */
  41.     int    callcount ;    /* recursion check counter */
  42.     int    alpha ;        /* 1 if an alphanumeric border exists */
  43.     unsigned short    *skip1, *skip2 ; /* Boyer-Moore search tables */
  44. } macro[MAX_MACROS], *macrop ;
  45.  
  46. int    defined_macros = 0 ;    /* number of defined macros */
  47.  
  48. /* function types */
  49. char    *expand_macros(), *mac_expand(), *search(), *strmatch() ;
  50. int    define_macro() ;
  51.  
  52.  
  53.  
  54.  
  55. /* Macro processor.
  56.  *
  57.  *   This routine defines and expands macros.  The definition phase
  58.  * is invoked when a leading : is found in the record.  Text is
  59.  * then taken until the terminating ; is found.  Text following the
  60.  * ; is ignored.  Multiline macros are permitted: they will be
  61.  * converted to at least as many lines in the fortran program.
  62.  * Failure to have a terminating ; will define the entire program
  63.  * to be a macro.
  64.  *   A NULL pointer is returned if a macro has been defined.  Otherwise
  65.  * a pointer to the buffer with the expanded text is returned (even if
  66.  * no macros have been expanded).  The buffer is temporary and should
  67.  * be eliminated by the caller.
  68.  */
  69.  
  70. char    *mac_proc()
  71. {
  72. int    i, j, size ;
  73. char    *text, *def ;
  74.  
  75.  
  76. /* see if this is a definition (look for leading :) */
  77. for ( i=0, text=NULL; in_buff[i] != NULL; i++ ) {
  78.     if ( in_buff[i] == BLANK | in_buff[i] == TAB ) continue ;
  79.     if ( in_buff[i] == ':' ) text = &in_buff[i] ;
  80.     break ;
  81. }
  82.  
  83. if ( text == NULL ) {
  84. /* expand macro if not a definition */
  85.     if ( defined_macros == 0 ) {
  86.         GET_MEM( text, strlen(in_buff) ) ;
  87.         strcpy( text, in_buff ) ;
  88.         return( text ) ;
  89.     }
  90.     else return( expand_macros( in_buff ) ) ;
  91.  
  92. }
  93. else {
  94.  
  95. /* macro definition, get characters until ; */
  96.     GET_MEM( def, strlen(text)+10 ) ;
  97.     strcpy( def, text ) ;
  98.     for ( j=1;; j++ ) {
  99.  
  100.         switch ( def[j] ) {
  101.  
  102.         case ';':    def[j+1] = NULL ;
  103.                 define_macro( def ) ;
  104.                 free( def ) ;
  105.                 return( NULL ) ;
  106.             
  107.         case NULL :    def[j] = '\n' ;
  108.                 def[j+1] = NULL ;
  109.                 if ( NULL == get_rec() )
  110.                     abort("MACRO: EOF in macro def") ;
  111.                 size = strlen(def) + strlen(in_buff) + 10 ;
  112.                 if ( NULL == (def=realloc(def,size)) )
  113.                     abort("MACRO: realloc error") ;
  114.                 strcat( def, in_buff ) ;
  115.         }
  116.     }
  117. }
  118. }
  119.  
  120.  
  121.  
  122.  
  123. /* Process the macro definition in the argument string.
  124.  * A macro has the form:
  125.  *
  126.  * : name( parm1, parm2, ... )    text with parms ;
  127.  *
  128.  * In a definition the delimeter must follow the name
  129.  * without whitespace.  In the source code this requirement is
  130.  * relaxed.  Alphanumeric macros must be not be next to an alpha or 
  131.  * number character or they will not be recognized.
  132.  *
  133.  * This routine puts the macro string into a more easily handled
  134.  * structure, replacing parms in the text with n, where n is a
  135.  * binary value (128 to 128+MAX_TOKENS).
  136.  *
  137.  * The macro is placed in a structure of the form:
  138.  *
  139.  * struct Macro {
  140.  *    char    *name ;
  141.  *    char    namelength ;
  142.  *    char    *text ;
  143.  *    int    parmcount ;
  144.  *    int    callcount ;
  145.  *    unsigned short    *skip1, *skip2 ;
  146.  * } macro[MAX_MACROS], *macrop ;
  147.  *
  148.  * where the text string has binary symbols where the parms were.
  149.  * Returns the macro index.  The number of macros defined is stored
  150.  * in global variable defined_macros.  Skip1 and skip2 are Boyer-Moore
  151.  * search tables.
  152.  * 
  153.  * The macros are entered in order of their name length, so that
  154.  * the macro expander will expand those with long names first.
  155.  *
  156.  * If no text is present the macro is removed from the list.
  157.  */
  158.  
  159. int    define_macro(string)
  160. char    *string ;
  161. {
  162. struct    Macro spare_macro ;
  163. char    *pntr, *pntr1, *name, *parms[MAX_TOKENS],
  164.     *parm, *text,
  165.     *open_parens, *close_parens ;
  166. int    i, j, l ;
  167.  
  168. /* macrop is a pointer to the macro structure that will be used */
  169.     if ( defined_macros >= MAX_MACROS ) {
  170.         sprintf(errline,"DEFINE_MACRO: too many macros: %s",string);
  171.         abort( errline ) ;
  172.     }
  173.     macrop = ¯o[defined_macros] ;
  174.     defined_macros++ ;
  175.  
  176. /* get the name */
  177.     name = strtokp( string, ":; \n\t(" ) ;    /* pointer to the name */
  178.     macrop->namelength = strlen(name) ;
  179.     GET_MEM( macrop->name, macrop->namelength ) ;
  180.     strcpy( macrop->name, name ) ;
  181.     macrop->alpha = isalnum( *macrop->name ) ||
  182.             isalnum( *(macrop->name + macrop->namelength - 1) ) ;
  183.  
  184. /* set up the Boyer-Moore skip tables */
  185.     if ( macrop->namelength > 1 ) makeskip( macrop ) ;
  186.     else {
  187.         macrop->skip1 = NULL ;
  188.         macrop->skip2 = NULL ;
  189.     }
  190.     
  191. /* get the parameters */
  192.     for ( i=0; i<MAX_TOKENS; i++ ) parms[i] = NULL ;
  193.     open_parens = strmatch(string,name) + macrop->namelength ;
  194.     if ( NULL == line_end( open_parens ) ) {
  195.         sprintf( errline, "DEFINE_MACRO: unterminated: %s", string ) ;
  196.         abort( errline ) ;
  197.     }
  198.  
  199.     /* get the text storage here to avoid memory allocation tangles */
  200.     text = open_parens ;
  201.     GET_MEM( macrop->text, strlen(text) ) ;
  202.  
  203.     if ( strchr( "([{\'\"", *open_parens ) ) {
  204.         if ( NULL == ( close_parens = mat_del( open_parens ) ) ) {
  205.             sprintf(errline,"DEFINE_MACRO: missing delimeter: %s",
  206.                 string ) ;
  207.             abort( errline ) ;
  208.         }
  209.         text = close_parens + 1 ;
  210.         i = (int)(close_parens - open_parens) - 1 ;
  211.         pntr = open_parens + 1 ;
  212.         *close_parens = NULL ;
  213.         for ( i=0, pntr1 = pntr; i<MAX_TOKENS; i++, pntr1 = NULL ) {
  214.             if ( NULL == ( parm = strtokp( pntr1, ", \t" ) ) )
  215.                 break ;
  216.             GET_MEM( parms[i], strlen(parm) ) ;
  217.             strcpy( parms[i], parm ) ;
  218.         }
  219.     }
  220.  
  221.     
  222. /* get the text, plugging in binary codes for parameters */
  223.  
  224.     /* remove leading whitespace */
  225.     if ( NULL == (text=line_end( text )) ) {
  226.         sprintf( errline, "DEFINE_MACRO: unterminated: %s", string ) ;
  227.         abort( errline ) ;
  228.     }
  229.  
  230.     /* remove the trailing ';' but NOT whitespace */
  231.     for ( i=strlen(text)-1; i>=0; i-- ) {
  232.         if ( text[i] == ';' ) { text[i] = NULL ; break ; }
  233.     }
  234.  
  235.     /* if the text is snow white at this stage, delete the entry
  236.      * and any other entries with the same name, then return.
  237.      */
  238.     if ( NULL == line_end(text) ) {
  239.         for ( i=defined_macros-2; i>=0; i-- ) {
  240.             if ( NULL == strcmp( macrop->name, macro[i].name ) ) {
  241.                 mac_del(i) ;
  242.                 macrop = ¯o[defined_macros-1] ;
  243.             }
  244.         }
  245.         mac_del(defined_macros-1) ;
  246.         return(-1) ;
  247.     }
  248.  
  249.     strcpy( macrop->text, text ) ;
  250.     text = macrop->text ;
  251.  
  252.     for ( i=0; i<MAX_TOKENS && NULL != (parm = parms[i]); i++ ) {
  253.  
  254.         /* replace parm by code, if not next to an alpha or number */
  255.         l = strlen(parm) ;
  256.         for ( pntr=text; NULL != (pntr1=strmatch(pntr,parm));
  257.         pntr=pntr1+1 ) {
  258.             if ( !( isalnum(*(pntr1-1)) && isalnum(*pntr1) ) &&
  259.                  !( isalnum(*(pntr1+l-1)) && isalnum(*(pntr1+l)))) {
  260.                      *pntr1 = i + 128 ;
  261.                 strcpy( pntr1 + 1, pntr1 + strlen(parm) ) ;
  262.             }
  263.         }
  264.     }
  265.  
  266.  
  267. /* count parms and free up temporary storage */
  268.     macrop->parmcount = 0 ;
  269.     for ( i=0; i<MAX_TOKENS && NULL != parms[i]; i++ ) {
  270.         free( parms[i] ) ;
  271.         macrop->parmcount++ ;
  272.     }
  273.  
  274. /* rearrange the macro table so it is sorted by name length */
  275.     for ( i=0; i<defined_macros-1; i++ ) {
  276.         if ( macrop->namelength < macro[i].namelength ) {
  277.             mac_copy( &spare_macro, macrop ) ;
  278.             for ( j=defined_macros-1; j>i; j-- )
  279.                 mac_copy( ¯o[j], ¯o[j-1] ) ;
  280.             mac_copy( ¯o[i], &spare_macro ) ;
  281.             break ;
  282.         }
  283.         /* replace if name already exists */
  284.         if ( macrop->namelength == macro[i].namelength &&
  285.              NULL == strcmp( macrop->name, macro[i].name ) ) {
  286.             mac_swap( ¯o[i], macrop ) ;
  287.             mac_del( defined_macros - 1 ) ;
  288.             break ;
  289.         }
  290.     }
  291.     
  292. /* return the index of the new macro */
  293.     return(i) ;
  294. }
  295.  
  296.  
  297.  
  298. /* MAC_COPY
  299.  *
  300.  * Copy macro p2 into p1 (just changing pointers)
  301.  */
  302. mac_copy( p1, p2 )
  303. struct Macro *p1, *p2 ;
  304. {
  305.     p1->name = p2->name ;
  306.     p1->namelength = p2->namelength ;
  307.     p1->text = p2->text ;
  308.     p1->parmcount = p2->parmcount ;
  309.     p1->callcount = p2->callcount ;
  310.     p1->alpha = p2 ->alpha ;
  311.     p1->skip1 = p2->skip1 ;
  312.     p1->skip2 = p2->skip2 ;
  313. }
  314.  
  315.  
  316.  
  317. /* MAC_SWAP
  318.  *
  319.  * Exchange macro contents.
  320.  */
  321. mac_swap( p1, p2 )
  322. struct Macro *p1, *p2 ;
  323. {
  324. struct Macro mac ;
  325.  
  326.     mac_copy( &mac, p1 ) ;
  327.     mac_copy( p1, p2 ) ;
  328.     mac_copy( p2, &mac ) ;
  329. }
  330.  
  331.  
  332.  
  333. /* MAC_DEL
  334.  *
  335.  * Remove a macro, specified by index, and shift the table.
  336.  */
  337.  
  338. /* the skip parameters may be null if the name is short */
  339. #define FREE(s)        if ( NULL != s ) free(s)
  340.  
  341. mac_del( i )
  342. int    i ;
  343. {
  344. int    j ;
  345.  
  346.     if ( i >= defined_macros ) return ;    /* index not defined */
  347.  
  348.     FREE( macro[i].name ) ;
  349.     FREE( macro[i].text ) ;
  350.     FREE( (char *)macro[i].skip1 ) ;
  351.     FREE( (char *)macro[i].skip2 ) ;
  352.     for ( j=i; j<defined_macros-1; j++ )
  353.         mac_copy( ¯o[j], ¯o[j+1] ) ;
  354.  
  355.     defined_macros-- ;
  356. }
  357.  
  358.  
  359.  
  360. /* Expand the macros in the argument string.  Returns a pointer
  361.  * to the expanded string, which is likely to be huge.  The memory
  362.  * should be freed as soon as possible.  The macros are expanded
  363.  * starting with the one with the highest index.  Recursive macro
  364.  * definitions will be flagged, but may cause a termination due to
  365.  * allocation failure before doing so.  Caution must be exercised
  366.  * to avoid accidental recursive definitions involving
  367.  * more than one macro:
  368.  *    : h    i+x ;
  369.  *    : i(y)    func(y) ;
  370.  *    : func    h ;
  371.  * This will generate the successive strings (from a = func(x)):
  372.  *    a = h(x)
  373.  *    a = i+x(x)
  374.  *    a = func()+x(x)
  375.  *    a = h()+x(x) .... and so on.  Beware.
  376.  * The string is deallocated by this routine.
  377.  */
  378.  
  379. /* macros to check for being next to an alpha */
  380. #define ALPHA_BEFORE(s)    ( (s!=text) && (isalnum(*(s-1)) && isalnum(*( s ))) )
  381. #define ALPHA_AFTER(s)    (               isalnum(*( s )) && isalnum(*(s+1))  )
  382. #define NEXT_TO_ALPHA(s,l)    ( ALPHA_AFTER(s+l-1) || ALPHA_BEFORE(s) )
  383.  
  384. char    *expand_macros(string)
  385. char    *string ;
  386. {
  387. char    *pntr, *candidate, *text, *stop ;
  388. int    i, hit, l ;
  389.  
  390. /* Allocate some initial storage */
  391.     GET_MEM( text, strlen(string) ) ;
  392.     strcpy( text, string ) ;
  393.  
  394. /* clear the recursion check counters */
  395.     for ( i=0; i<defined_macros; i++ ) macro[i].callcount = 0 ;
  396.  
  397. /* search for macros */
  398.     do {
  399.     stop = text + strlen(text) - 1 ; /* length changed in mac_expand */
  400.  
  401.     for ( i=defined_macros-1; i>=0; i-- ) {
  402.         hit = 0 ;        
  403.         l = macro[i].namelength ;
  404.          quoted( text, text ) ;    /* reset the quote function */
  405.          
  406.     /* See if macro[i] is in the present string.  If the "edges"
  407.      * of the macro name are alphanumeric, don't accept the string
  408.      * if the adjacent character is also alphanumeric.  This avoids
  409.      * having variables such as "arg" flagged if "r" is defined.
  410.      * Potential macros are also rejected if quoted with '.
  411.      */
  412.         for ( pntr=text;; pntr=candidate+1 ) {
  413.             if ( macro[i].namelength == 1 )
  414.                 candidate = strchr( pntr, macro[i].name[0] ) ;
  415.             else
  416.                 candidate = search( pntr, stop, ¯o[i] ) ;
  417.             if ( candidate == NULL ) break ;
  418.  
  419.             /* see if its not an illusion, easiest checks 1st */
  420.             if ( macro[i].alpha && NEXT_TO_ALPHA(candidate,l) )
  421.                 continue ;
  422.             if ( quoted( candidate, NULL ) ) continue ;
  423.  
  424.             /* got one */
  425.             hit = 1 ;
  426.             text = mac_expand( text, candidate, i ) ;
  427.             break ;
  428.         }
  429.         if ( hit != 0 ) break ;    /* start over if one was found */
  430.     }
  431.     } while( hit != 0 ) ; 
  432.  
  433.  
  434.     return( text ) ;
  435. }
  436.  
  437.  
  438.  
  439. /* Expand a single macro in a text string, freeing the old storage
  440.  * and returning a pointer to the new string.  Name points to the
  441.  * macro in the string and index is the macro index.
  442.  */
  443.  
  444. char    *mac_expand( text, name, index )
  445. char    *text, *name ;
  446. int    index ;
  447. {
  448. char    *pntr, *newtext, *parm, *parms[MAX_TOKENS], *temp,
  449.     *open_parens, *close_parens, *rest_of_text ;
  450. int    i, j, size ;
  451. unsigned char     c ;
  452.  
  453.     macrop = ¯o[index] ;
  454.     if ( macrop->callcount++ > MAX_CALLS ) {
  455.         sprintf( errline,
  456.         "MAC_EXPAND: possible recursion involving: \'%s\' in\n%s",
  457.             macrop->name, in_buff ) ;
  458.         abort( errline ) ;
  459.     }
  460.     
  461.  
  462. /* get the parameters if there are any for this macro */
  463.     for ( i=0; i<MAX_TOKENS; i++ ) parms[i] = NULL ;
  464.     rest_of_text = &name[ macrop->namelength ] ;
  465.     if ( macrop->parmcount != 0 ) {
  466.         open_parens = &rest_of_text[ strspn( rest_of_text, " \t" ) ] ;
  467.         if ( (NULL != strchr( "([{\'\"", *open_parens )) &&
  468.              (NULL != *open_parens )) {
  469.             if (NULL == (close_parens=mat_del(open_parens)) ) {
  470.                 sprintf( errline,
  471.                 "MAC_EXPAND: missing delimeter: %s", in_buff ) ;
  472.                 abort( errline ) ;
  473.             }
  474.             i = (int)(close_parens - open_parens) - 1 ;
  475.             pntr = open_parens + 1 ;
  476.             c = *close_parens ;        /* save *close_parens */
  477.             *close_parens = NULL ;        /* make parm block a string */
  478.             i = tokenize( pntr, parms ) ;    /* break out the parms */
  479.             *close_parens = (char)c ;     /* restore text */
  480.             rest_of_text = close_parens + 1 ;
  481.         }
  482.     }
  483.  
  484.     
  485. /* find out how much memory we will need, then allocate */
  486.     size = strlen(text) ;
  487.     if ( NULL != ( pntr = macrop->text ) ) size += strlen(pntr) ;
  488.     for ( i=0; NULL != (c=pntr[i]); i++ ) {
  489.         if ( c > 127 && parms[c-128] != NULL )
  490.             size += strlen(parms[c-128]) ;
  491.     }
  492.     GET_MEM( newtext, size ) ;
  493.  
  494.  
  495. /* copy up to macro verbatim */
  496.     *name = NULL ;
  497.     strcpy( newtext, text ) ;
  498.  
  499. /* expand the macro itself if there is text */
  500.     if ( NULL != (pntr = macrop->text) ) {
  501.         for ( i=0, j=strlen(newtext); NULL != (c=pntr[i]); i++, j++ ) {
  502.             if ( c > 127 ) {
  503.                 if ( parms[c-128] != NULL ) {
  504.                     strcat( newtext, parms[c-128] ) ;
  505.                     j += strlen( parms[c-128] ) - 1 ;
  506.                 }
  507.                 else j-- ;
  508.             }
  509.             else {        /* keep null terminated */
  510.                 newtext[j] = c ;
  511.                 newtext[j+1] = NULL ;
  512.             }
  513.         }
  514.     }
  515.     
  516.  
  517. /* finish off trailing text */
  518.     strcat( newtext, rest_of_text ) ;
  519.     
  520. /* free up temporary storage and return pointer to new allocation */
  521.     for ( i=0; i<MAX_TOKENS && NULL != parms[i]; i++ ) free( parms[i] ) ;
  522.     free( text ) ;
  523.     return( newtext ) ;
  524. }
  525.  
  526.  
  527.  
  528.  
  529. /* isalnum: returns nonzero value if the character argument belongs to the 
  530.  * sets { a-z, A-Z, 0-9 }.
  531.  */
  532.  
  533. int    isalnum( c )
  534. char    c ;
  535. {
  536.     if ( c >= 97 && c <= 122 ) return (1) ;    /* a-z */
  537.     if ( c >= 65 && c <= 90 ) return (2) ;    /* A-Z */
  538.     if ( c >= 48 && c <= 57 ) return (3) ;    /* 0-9 */
  539.     return(0) ;                /* miss */
  540. }
  541.  
  542.  
  543.  
  544.  
  545. /* Return TRUE if the pointer is quoted in the string (pntr marks
  546.  * a position in the string).  The quote character the apostrophe.
  547.  * If pntr is not in the the result will be meaningless.  This
  548.  * routine keeps a static index and quote flag, so it doesn't have
  549.  * to keep starting back at the beginning.  To reset it, call with
  550.  * string != NULL pointer.  Subsequent calls should have string NULL,
  551.  * and pntr >= the original string.  Since macros can be on multiple
  552.  * lines, the quote flag is reset on newline.
  553.  */
  554.  
  555. int    quoted( pntr, s )
  556. char    *pntr, *s ;
  557. {
  558. static int    i, quote ;
  559. static char    *string ;
  560.  
  561.     if ( s != NULL ) {
  562.         i = 0 ;
  563.         quote = FALSE ;
  564.         string = s ;
  565.     }
  566.     else {
  567.         for ( ; NULL != string[i] && &string[i] < pntr; i++ ) {
  568.             switch ( string[i] ) {
  569.                 case '\'':    quote = !quote ; break ;
  570.                 case '\n':    quote = FALSE ;
  571.             }
  572.         }
  573.     }
  574.         
  575.     return( quote ) ;
  576. }
  577.  
  578.  
  579.  
  580.  
  581.  
  582.  
  583.  
  584. /* Guts of the Boyer-Moore algorithm, using already defined skip tables.
  585.  * Returns a pointer to the location where the text is found, else a
  586.  * NULL pointer.
  587.  */
  588.  
  589. char *search( start, stop, macrop )
  590. char            *start, *stop ;        /* 1st and last in buffer */
  591. struct Macro        *macrop ;
  592.  
  593. {
  594. register char     *k,        /* indexes text */
  595.         *j ;        /* indexes pattern */
  596. register int    skip ;        /* skip distance */
  597. char        *patend ;    /* pointer to last char in pattern */
  598.  
  599. patend = macrop->name + macrop->namelength - 1 ;
  600.  
  601.     k = start ;
  602.     skip = macrop->namelength - 1 ;
  603.     while ( skip <= (stop-k) ) {
  604.  
  605.         for ( j=patend, k=k+skip; *j == *k; --j, --k )
  606.             if ( j == macrop->name ) return(k) ;
  607.  
  608.         skip = max( macrop->skip1[ *(unsigned char *)k ],
  609.                 macrop->skip2[ j - macrop->name ]      ) ;
  610.     }
  611.  
  612.     /* reaching here ==> search failed */
  613.     return(NULL) ;
  614. }
  615.  
  616.  
  617.  
  618.  
  619. /* Generate the skip tables for Boyer-Moore string search algorithm.
  620.  * Skip1 is the skip depending on the character which failed to match
  621.  * the pattern (name), and skip2 is the skip depending on how far we
  622.  * got into the name.
  623.  */
  624.  
  625. makeskip( macrop )
  626. struct Macro *macrop ;
  627. {
  628. char    *name, *p ;
  629. unsigned short    *skip1, *skip2 ;
  630. int    namelength ;
  631. int    *backtrack ;    /* backtracking table for t when building skip2 */
  632. int    c ;        /* general purpose constant */
  633. int    j, k, t, tp ;    /* indices into skip's and backtrack */
  634.  
  635.     
  636.     name = macrop->name ;
  637.     namelength = macrop->namelength ;
  638.  
  639.     /* allocate space for the skip strings */ 
  640.     GET_MEM( p, sizeof(int) * (MAXCHAR + 1) ) ;
  641.     skip1 = (unsigned short int *)p ;
  642.     GET_MEM( p, sizeof(int) * namelength ) ;
  643.     skip2 = (unsigned short int *)p ;
  644.     
  645.     macrop->skip1 = skip1 ;
  646.     macrop->skip2 = skip2 ;
  647.     
  648.     /* allocate temporary space for the backtracking table */
  649.     GET_MEM( p, sizeof(int) * namelength ) ;
  650.     backtrack = (int *)p ;
  651.     
  652.     for (c=0; c<=MAXCHAR; ++c) skip1[c] = namelength ;
  653.  
  654.     for (k=0; k<namelength; k++) {
  655.         skip1[name[k]] = namelength - k - 1 ;
  656.         skip2[k] = 2 * namelength - k - 1 ;
  657.     }
  658.  
  659.     for (j=namelength - 1,t=namelength; j >= 0; --j,--t) {
  660.         backtrack[j] = t ;
  661.         while (t<namelength && name[j] != name[t]) {
  662.             skip2[t] = min(skip2[t], namelength - j - 1) ;
  663.             t = backtrack[t] ;
  664.         }
  665.     }
  666.  
  667.     for (k=0; k<=t; ++k) skip2[k] = min(skip2[k],namelength+t-k) ;
  668.     tp=backtrack[t] ;
  669.  
  670.     while( tp < namelength ) {
  671.         while( t < namelength ) {
  672.             skip2[t] = min( skip2[t], tp-t+namelength ) ;
  673.             ++t ;
  674.         }
  675.         tp = backtrack[tp] ;
  676.     }
  677.  
  678.     free(backtrack) ;
  679. }
  680.  
  681.  
  682.  
  683. /* MAC_QUERY
  684.  *
  685.  * Determine if a given string a defined macro.  Returns the index of
  686.  * the macro, or -1 on failure.  The list is assumed sorted by length.
  687.  */
  688. int    mac_query( s )
  689. char    *s ;
  690. {
  691. int    index, i, l ;
  692.  
  693.     l = strlen( s ) ;
  694.  
  695.     /* Find first macro with length l (need not be efficient here) */
  696.     for ( index=0; index<defined_macros; index++ ) {
  697.         if ( macro[index].namelength==l ) break ;
  698.         if ( macro[index].namelength>l || index==defined_macros-1 )
  699.             return(-1) ;
  700.     }
  701.  
  702.     /* Look for a match */
  703.     for ( i=index; macro[i].namelength==l && i<defined_macros; i++ ) {
  704.         if ( NULL == strcmp( s, macro[i].name ) ) return(i) ;
  705.     }
  706.  
  707.     return(-1) ;
  708. }
  709.